%{
#include "DTD.h"
#include "StructureDTD.h"
#include "CardDTD.h"
#include <vector>
#include "EmptyDTD.h"
#include "AnyDTD.h"
#include "PCDataDTD.h"
#include "ChoiceDTD.h"
#include "SequenceDTD.h"
#include "IdentDTD.h"
#include "CardDTD.h"
#include "AttributeDTD.h"
#include "ElementDTD.h"

void dtderror(DTD **d, char *msg);
int dtdwrap(void);
int dtdlex(void);
%}

%union { 
   	char *s;
	class DTD * dtd;
	class AttributeDTD * a;
	std::vector<AttributeDTD*>* la;
	enum Card card;
	class StructureDTD * stru;
	class ComponentDTD * comp;
	enum Type t;
	enum Necessity n;
	std::vector<string>* vs;
   }

%token ELEMENT ATTLIST CLOSE OPENPAR CLOSEPAR COMMA PIPE FIXED PCDATA AST QMARK PLUS CDATA
%token <s> IDENT TOKENTYPE DECLARATION STRING
%token <stru> EMPTY ANY
%type <dtd> main dtd_list_opt
%type <a> attribute
%type <la> att_definition_opt
%type <card> card_opt
%type <stru> contentspec children mixed choice_card seq_card choice_list_plus choice_list choice seq seq_list name
%type <comp> cp
%type <t> att_type
%type <n> default_declaration;
%type <vs> enumerate enum_list_plus enum_list 
%type <s> item_enum

%parse-param {DTD ** dtd}

%start main
%%

main: dtd_list_opt { $$ = $1; }
    ;

dtd_list_opt
: dtd_list_opt ATTLIST IDENT att_definition_opt CLOSE 
{
	$$ = $1;

	/*ElementDTD* elem = $$->getElementByName($3); // get the element corresponding to IDENT
	if(elem == NULL)
	{
		char err[50];
		sprintf(err, "Element named \"%s\" doesn't exist\n", $3);
		dtderror(NULL, err);
	}

	else
	{*/
		printf("ON VA AJOUTER LES ATTRIBUTS\n\n");
		/* for each attribute in att_definition_opt, we add it to the list of attributes of elem */
		for(unsigned int i=0; i<$4->size(); i++)
		{
			//elem->addAttribute( (*$4)[i] );
			printf("111111111111111\n");
			(*$4)[i]->setElementAssociated($3);
			printf("22222222222222\n");
			$$->addAttribute( (*$4)[i] );
			printf("ATTRIBUT AJOUTE\n\n");
		}
	//}

};
| dtd_list_opt ELEMENT IDENT contentspec CLOSE
{
	$$ = $1;
	ElementDTD* newElem = new ElementDTD($3, $4);
	int res = $$->addElement($3, newElem);
	if(res == -1) /* means the element couldn't be inserted in the map */
	{
		char err[50];
		sprintf("Element name \"%s\" already exists\n", $3);
		dtderror(NULL, err);
	}
	printf("ELEMENT AJOUTE\n\n");
}       
| /* empty */   
{ $$ = new DTD;
  *dtd = $$;
}                  
;

contentspec
: EMPTY { $$ = new EmptyDTD; }
| ANY	{ $$ = new AnyDTD; }
| children { $$ = $1; }
| mixed { $$ = $1; }
;

children
: choice_card { $$ = $1; }
| seq_card { $$ = $1; }
;

choice_card
: choice card_opt 
{ 	$$ = $1; 
	((ChoiceDTD*)$$)->setCard($2);
}
;

seq_card
: seq card_opt
{ 	$$ = $1; 
	((SequenceDTD*)$$)->setCard($2);
}
;

card_opt
: QMARK {$$ = ZERO_ONE;}
| PLUS  { $$ = ONE_N; }
| AST	{ $$ = ZERO_N; }
| /*VIDE */ {$$ = ONE; }
;

choice 
: OPENPAR choice_list_plus CLOSEPAR { $$ = $2;}
;

choice_list_plus
: cp PIPE choice_list 
{ 	$$ = $3;
	((ChoiceDTD*)$$)->addComponent($1);
}
;

choice_list 
: choice_list PIPE cp 
{ 	$$ = $1;
	((ChoiceDTD*)$$)->addComponent($3); 
}
| cp 
{ 	$$ = new ChoiceDTD;
	((ChoiceDTD*)$$)->addComponent($1); 
}
;

seq
: OPENPAR seq_list CLOSEPAR { $$ = $2; }
;

seq_list
: seq_list COMMA cp
{ 	$$ = $1;
	((SequenceDTD*)$$)->addComponent($3);
}
| cp 
{	$$ = new SequenceDTD;
	((SequenceDTD*)$$)->addComponent($1);
}
;

cp
: IDENT card_opt { $$ = new IdentDTD($1, $2); }
| choice_card	{ $$ = $1; }
| seq_card	{ $$ = $1; }
;
 
mixed
: OPENPAR PCDATA name CLOSEPAR AST
{
	$$ = $3;
	((ComposedStructDTD*)$$)->addComponent( new PCDataDTD );
	((ComposedStructDTD*)$$)->setCard( ZERO_N );
}
| OPENPAR PCDATA CLOSEPAR
{	$$ = new SequenceDTD; 
	((ComposedStructDTD*)$$)->addComponent( new PCDataDTD );
}
;

name
: name PIPE IDENT
{
	$$ = $1;
	((ComposedStructDTD*)$$)->addComponent( new IdentDTD($3, ONE) );
}
| PIPE IDENT 
{ 
	$$ = new ChoiceDTD; 
	((ComposedStructDTD*)$$)->addComponent( new IdentDTD($2, ONE) );
}
;

att_definition_opt
: att_definition_opt attribute { $$ = $1; $$->push_back($2); }
| /* empty */ {$$ = new vector<AttributeDTD*>; }
;

attribute
: IDENT att_type default_declaration { printf("NEW ATTRIBUTE\n\n"); $$ = new AttributeDTD($1, $2, $3); }
;

att_type
: CDATA {$$ = Cdata; }
| TOKENTYPE {$$ = Atom; } /* A AMELIORER SI ON A LE TEMPS */
| enumerate { $$ = Enum	} /* A AMELIORER SI ON A LE TEMPS */
;

enumerate
: OPENPAR enum_list_plus CLOSEPAR { $$ = $2; }
;

enum_list_plus
: enum_list PIPE item_enum { $$ = $1; $1->push_back($3); }
;

enum_list
: item_enum  { $$ = new vector<string> ; $$->push_back($1); }             
| enum_list PIPE item_enum { $$ = $1; $$->push_back($3) }
;

item_enum
: IDENT { $$ = $1; }
;

default_declaration
: DECLARATION {$$ = Implied; } /* A AMELIORER SI ON A LE TEMPS */
| STRING {$$ = Implied; }
| FIXED STRING {$$ = Implied; }
;


%%
/* The main must be commented for integration */
int main(int argc, char **argv)
{
  int err;

  //dtddebug = 1; // pour désactiver l'affichage de l'exécution du parser LALR, commenter cette ligne
  DTD* d;
  err = dtdparse(&d);
  if (err != 0) printf("Parse ended with %d error(s)\n", err);
        else  printf("Parse ended with success\n", err);

  printf("\n\nChecking validity of the DTD : \n");
  if (d->makeDTD() == -1)
  {
	printf("The DTD is not valid");
  }

  d->display();

  

  return 0;
}



int dtdwrap(void)
{
  return 1;
}

void dtderror(DTD** d, char *msg)
{
  fprintf(stderr, "%s\n", msg);
}


